Skip to content

Conversation

197g
Copy link
Contributor

@197g 197g commented Aug 9, 2025

There are a few alternatives to the implementation. The principal problem is that the selected value must be owned (in the sense of having a drop flag of sorts) when the unselected value is dropped, such that panic unwind goes through the drop of both. This ownership must then be passed on in return when the drop went smoothly.

The basic way of achieving this is by extracting the selected value first, at the cost of relying on the optimizer a little more for detecting the copy as constructing the return value despite having a place in the body. Unfortunately, that causes LLVM to discard the !unpredictable annotation (for some reason that is beyond my comprehension of LLVM).

Extract from the build log showing an unannotated select being used
2025-08-09T16:51:06.8790764Z            39: define noundef i64 @test_int2(i1 noundef zeroext %p, i64 noundef %a, i64 noundef %b) unnamed_addr #0 personality ptr @rust_eh_personality { 
2025-08-09T16:51:06.8791368Z check:47'0                                  X~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: no match found
2025-08-09T16:51:06.8791700Z            40: start: 
2025-08-09T16:51:06.8791858Z check:47'0     ~~~~~~~
2025-08-09T16:51:06.8792043Z            41:  %ret.i = select i1 %p, i64 %a, i64 %b 
2025-08-09T16:51:06.8792293Z check:47'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2025-08-09T16:51:06.8792686Z check:47'1               ?                             possible intended match
2025-08-09T16:51:06.8792946Z            42:  ret i64 %ret.i 
2025-08-09T16:51:06.8793127Z check:47'0     ~~~~~~~~~~~~~~~~

So instead, this PR includes a guard to drop the selected MaybeUnit<T> which is active only for the section where the unselected value is dropped. That leaves the code for selecting the result intact leading to the expected ir. That complicates the 'unselection' process a little bit since we require both values as a result of that intrinsic call. Since the arguments alias, this portion as well as the drop guard uses raw pointers.

Closes: #145148
Prior: #139977

There are a few alternatives to the implementation. The principal
problem is that the selected value must be owned (in the sense of having
any drop flag of sorts) when the unselected value is dropped, such that
panic unwind goes through the drop of both. This ownership must then be
passed on in return when the drop went smoothly. The basic way of
achieving this is by extracting the selected value first, at the cost of
relying on the optimizer a little more for detecting the copy as
constructing the return value despite having a place in the body.
@rustbot
Copy link
Collaborator

rustbot commented Aug 9, 2025

r? @thomcc

rustbot has assigned @thomcc.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Aug 9, 2025
@197g 197g changed the title Ensure consistent drop for hint::select_unpredictable Ensure consistent drop for panicking drop in hint::select_unpredictable Aug 9, 2025
@rust-log-analyzer

This comment has been minimized.

It seems important for LLVM that we select on the values by-value
instead of reading and have no intermediate store. So make sure the
guards selects both potential drops but defers the return value to the
second selection. Since the two options alias we use raw mutable
pointers instead of mutable references as before.
197g added 3 commits August 30, 2025 13:01
Instead of a tuple, select the dropped value and its guard with two
separate calls to the intrinsic which makes both calls have a
pointer-valued argument that should be simpler in codegen. Use the same
condition on all (not an inverted condition) to clarify the intent of
parallel selection. This should also be a simpler value-dependency chain
if the guard is deduced unused (i.e. drop_in_place a noop for the type).
@197g 197g force-pushed the issue-145148-select-unpredictable-drop branch from f1c2b28 to ee9803a Compare August 30, 2025 11:01
@joboet
Copy link
Member

joboet commented Aug 31, 2025

@bors r+

@bors
Copy link
Collaborator

bors commented Aug 31, 2025

📌 Commit ee9803a has been approved by joboet

It is now in the queue for this repository.

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Aug 31, 2025
@joboet joboet assigned joboet and unassigned thomcc Aug 31, 2025
bors added a commit that referenced this pull request Aug 31, 2025
Rollup of 4 pull requests

Successful merges:

 - #144443 (Make target pointer width in target json an integer)
 - #145174 (Ensure consistent drop for panicking drop in hint::select_unpredictable)
 - #145592 (Fix format string grammar in docs and improve alignment error message for #144023)
 - #145931 (Clarify that align_offset overaligns)

r? `@ghost`
`@rustbot` modify labels: rollup
@bors bors merged commit 59a645a into rust-lang:master Aug 31, 2025
10 checks passed
@rustbot rustbot added this to the 1.91.0 milestone Aug 31, 2025
rust-timer added a commit that referenced this pull request Aug 31, 2025
Rollup merge of #145174 - 197g:issue-145148-select-unpredictable-drop, r=joboet

Ensure consistent drop for panicking drop in hint::select_unpredictable

There are a few alternatives to the implementation. The principal problem is that the selected value must be owned (in the sense of having a drop flag of sorts) when the unselected value is dropped, such that panic unwind goes through the drop of both. This ownership must then be passed on in return when the drop went smoothly.

The basic way of achieving this is by extracting the selected value first, at the cost of relying on the optimizer a little more for detecting the copy as constructing the return value despite having a place in the body. Unfortunately, that causes LLVM to discard the !unpredictable annotation (for some reason that is beyond my comprehension of LLVM).

<details>
<summary>Extract from the build log showing an unannotated select being used</summary>

```
2025-08-09T16:51:06.8790764Z            39: define noundef i64 `@test_int2(i1` noundef zeroext %p, i64 noundef %a, i64 noundef %b) unnamed_addr #0 personality ptr `@rust_eh_personality` {
2025-08-09T16:51:06.8791368Z check:47'0                                  X~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: no match found
2025-08-09T16:51:06.8791700Z            40: start:
2025-08-09T16:51:06.8791858Z check:47'0     ~~~~~~~
2025-08-09T16:51:06.8792043Z            41:  %ret.i = select i1 %p, i64 %a, i64 %b
2025-08-09T16:51:06.8792293Z check:47'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2025-08-09T16:51:06.8792686Z check:47'1               ?                             possible intended match
2025-08-09T16:51:06.8792946Z            42:  ret i64 %ret.i
2025-08-09T16:51:06.8793127Z check:47'0     ~~~~~~~~~~~~~~~~
```

</details>

So instead, this PR includes a guard to drop the selected `MaybeUnit<T>` which is active only for the section where the unselected value is dropped. That leaves the code for selecting the result intact leading to the expected ir. That complicates the 'unselection' process a little bit since we require _both_ values as a result of that intrinsic call. Since the arguments alias, this portion as well as the drop guard uses raw pointers.

Closes: #145148
Prior: #139977
github-actions bot pushed a commit to rust-lang/compiler-builtins that referenced this pull request Sep 1, 2025
Rollup of 4 pull requests

Successful merges:

 - rust-lang/rust#144443 (Make target pointer width in target json an integer)
 - rust-lang/rust#145174 (Ensure consistent drop for panicking drop in hint::select_unpredictable)
 - rust-lang/rust#145592 (Fix format string grammar in docs and improve alignment error message for rust-lang/rust#144023)
 - rust-lang/rust#145931 (Clarify that align_offset overaligns)

r? `@ghost`
`@rustbot` modify labels: rollup
github-actions bot pushed a commit to rust-lang/miri that referenced this pull request Sep 1, 2025
Rollup of 4 pull requests

Successful merges:

 - rust-lang/rust#144443 (Make target pointer width in target json an integer)
 - rust-lang/rust#145174 (Ensure consistent drop for panicking drop in hint::select_unpredictable)
 - rust-lang/rust#145592 (Fix format string grammar in docs and improve alignment error message for rust-lang/rust#144023)
 - rust-lang/rust#145931 (Clarify that align_offset overaligns)

r? `@ghost`
`@rustbot` modify labels: rollup
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-libs Relevant to the library team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

hint::select_unpredictable forgets to drop one argument if dropping another panics.
6 participants